﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DTOSW.Core.Membership.Functions;
using DTOSW.Core.Membership.Interfaces.Repositories;
using DTOSW.Core.Membership.Objects.Model;
using DTOSW.Core.Membership.Security;

namespace DTOSW.Data.Membership.Integration.Repositories
{
    public class MembershipRepository : IMembershipRepository
    {
        private readonly UserDataBaseDataContext dataContext;

        public MembershipRepository()
        {
            dataContext = new UserDataBaseDataContext();
        }
        public MembershipRepository(UserDataBaseDataContext dataContext)
        {
            this.dataContext = dataContext;
        }

        public IQueryable<User> GetUser()
        {
            return from users in dataContext.Users
                   select new User {
                       UserID = users.UserID,
                       UserName = users.UserName,
                       LoweredUserName = users.LoweredUserName,
                       LastActivityDate = users.LastActivityDate,
                       Password = ConvertToModelPassword(users.Password),
                       Profile = ConvertToModelProfile(users.Profile),
                       Roles = (from role in users.UserInRoles
                                select ConvertToModelRole(role.Role)).ToList(),

                   };
        }
        
        public CreationStatus CreateUser(string username, string password, string email)
        {
            //Get CustomerID before add new User
            Core.Membership.Functions.PasswordEncrypt passwordEncrypt = new PasswordEncrypt();

            Entities.User newMemberToUser = new Entities.User {
                UserID = Guid.NewGuid(),
                UserName = username,
                LoweredUserName = username.ToLower(),
                LastActivityDate = DateTime.Now,
            };
            dataContext.Users.InsertOnSubmit(newMemberToUser);


            Entities.Password newMemberToPassword = new Entities.Password {
                UserID = newMemberToUser.UserID,
                UserPassword = password,
                CreateDate = DateTime.Now,
                IsLockedOut = false,
                IsApproved = true,
                LastLoginDate = DateTime.Now,
                FailedPasswordAttemptCount = 0,
                FailedPasswordAttemptWindowStart = DateTime.Now,
                LastLockoutDate = DateTime.Now,
                LastPasswordChangedDate = DateTime.Now
            };

            dataContext.Passwords.InsertOnSubmit(newMemberToPassword);

            Entities.Profile newMemberProfile = new Entities.Profile {
                UserID = newMemberToUser.UserID
            };
            dataContext.Profiles.InsertOnSubmit(newMemberProfile);

            Entities.Mail newMemberMail = new Entities.Mail {
                UserID = newMemberToUser.UserID,
                Email = email,
                LoweredEmail = email.ToLower(),
                PrimaryMail = true
            };

            dataContext.Mails.InsertOnSubmit(newMemberMail);
            dataContext.SubmitChanges();

            return CreationStatus.Success;
        }

        public UpdateStatus UpdateProfile(Profile profile)
        {
            Entities.Profile existingProfile = (from eProfile in dataContext.Profiles
                                                where eProfile.UserID == profile.UserID
                                                select eProfile).SingleOrDefault();


            if (existingProfile == null)
                return UpdateStatus.ProfileNotExist;

            existingProfile.FirstName = profile.FirstName;
            existingProfile.LastName = profile.LastName;

            existingProfile.Address = profile.Address;
            existingProfile.City = profile.City;
            existingProfile.Country = profile.Country;

            existingProfile.LastChangedProfile = profile.LastChangedProfile;
            existingProfile.Phone = profile.Phone;
            existingProfile.PostalCode = profile.PostalCode;
            existingProfile.sex = profile.sex;

            if (profile.Mails != null) {
                foreach (var mail in profile.Mails) {
                    Entities.Mail existingMail = existingProfile.Mails.Where(x => x.MailID == mail.MailID).SingleOrDefault();

                    if (existingMail == null) {
                        var newMail = new Entities.Mail();
                        ConvertToEntityMail(newMail, mail);
                        dataContext.Mails.InsertOnSubmit(newMail);
                    }
                    else {
                        ConvertToEntityMail(existingMail, mail);
                    }
                }
            }

            dataContext.SubmitChanges();

            return UpdateStatus.Success;
        }

        public DeleteStatus DeleteUser(Guid userID)
        {
            Entities.User userToDelete = (from users in dataContext.Users
                                          where users.UserID == userID
                                          select users).SingleOrDefault();

            if (userToDelete == null)
                return DeleteStatus.UserNotExist;

            dataContext.Profiles.DeleteAllOnSubmit((from profiles in dataContext.Profiles where profiles.UserID == userID select profiles));
            dataContext.Passwords.DeleteAllOnSubmit((from paswords in dataContext.Passwords where paswords.UserID == userID select paswords));
            dataContext.UserInRoles.DeleteAllOnSubmit((from userInRoles in dataContext.UserInRoles where userInRoles.UserID == userID select userInRoles));
            dataContext.Mails.DeleteAllOnSubmit((from mails in dataContext.Mails where mails.UserID == userID select mails));

            dataContext.Users.DeleteOnSubmit(userToDelete);
            dataContext.SubmitChanges();

            return DeleteStatus.Success;
        }
        
        public void ChangePassword(Guid userID, string currentPassword, string newPassword)
        {
            if (userID == Guid.Empty || currentPassword == string.Empty || newPassword == string.Empty)
                throw new NullReferenceException("Some arguments is empty");

            Entities.Password existingPassword = (from ePassword in dataContext.Passwords
                                                  where ePassword.UserID == userID
                                                  select ePassword).SingleOrDefault();

            if (currentPassword != existingPassword.UserPassword)
                throw new Exception("The retyped password do not match");


            existingPassword.UserPassword = newPassword;

            existingPassword.LastPasswordChangedDate = DateTime.Now;

            dataContext.SubmitChanges();

        }

        public UserValidateStatus ValidateUser(string username, string password)
        {
            Entities.User existingUser = (from eUser in dataContext.Users where eUser.UserName == username select eUser).SingleOrDefault();

            if(existingUser == null)
                return UserValidateStatus.InvalidUserName;

            if (existingUser.Password.UserPassword != password)
                return UserValidateStatus.InValidPassword;

            return UserValidateStatus.Success;
        }

        #region < Private Entities Methods >
        private Entities.Profile ConvertToEntityProfile(Profile profile)
        {
            return new Entities.Profile {
                UserID = profile.UserID,
                FirstName = profile.FirstName,
                LastName = profile.LastName,
                Address = profile.Address,
                City = profile.City,
                Country = profile.Country,
                Phone = profile.Phone,
                PostalCode = profile.PostalCode,
                sex = profile.sex,
                LastChangedProfile = DateTime.Now
                //Mails.For

                //= (from mails in profile.Mails select ConvertToEntityMail(mails)) as EntitySet<Entities.Mail>

            };
        }
        private void ConvertToEntityMail(Entities.Mail existingMail, Mail mail)
        {
            existingMail.Email = mail.Email;
            existingMail.LoweredEmail = mail.LoweredEmail;
            existingMail.MailID = mail.MailID;
            existingMail.MailType = mail.MailType;
            existingMail.PrimaryMail = mail.PrimaryMail;
            existingMail.UserID = mail.UserID;
        }
        private Entities.Password ConvertToEntityMail(Password password)
        {
            return new Entities.Password() {
                UserID = password.UserID,
                UserPassword = password.UserPassword,
                IsApproved = password.IsApproved,
                IsLockedOut = password.IsLockedOut,
                CreateDate = password.CreateDate,
                LastLoginDate = password.LastLoginDate,
                LastPasswordChangedDate = password.LastPasswordChangedDate,
                LastLockoutDate = password.LastLockoutDate,
                FailedPasswordAttemptCount = password.FailedPasswordAttemptCount,
                FailedPasswordAttemptWindowStart = password.FailedPasswordAttemptWindowStart
            };

        }
        #endregion

        #region < Private Model Methods >
        private Password ConvertToModelPassword(Entities.Password password)
        {
            return new Password {
                UserID = password.UserID,
                UserPassword = password.UserPassword,
                IsApproved = password.IsApproved,
                IsLockedOut = password.IsLockedOut,
                CreateDate = password.CreateDate,
                LastLoginDate = password.LastLoginDate,
                LastPasswordChangedDate = password.LastPasswordChangedDate,
                LastLockoutDate = password.LastLockoutDate,
                FailedPasswordAttemptCount = password.FailedPasswordAttemptCount,
                FailedPasswordAttemptWindowStart = password.FailedPasswordAttemptWindowStart
            };
        }
        private Profile ConvertToModelProfile(Entities.Profile profile)
        {
            return new Profile {
                Address = profile.Address,
                City = profile.City,
                Country = profile.Country,
                FirstName = profile.FirstName,
                LastChangedProfile = profile.LastChangedProfile,
                LastName = profile.LastName,
                Phone = profile.Phone,
                PostalCode = profile.PostalCode,
                sex = profile.sex,
                UserID = profile.UserID,
                Mails = (from mails in profile.Mails
                         select ConvertToModelMails(mails)).ToList()
            };
        }
        private Mail ConvertToModelMails(Entities.Mail mail)
        {
            return new Mail {
                Email = mail.Email,
                LoweredEmail = mail.LoweredEmail,
                MailID = mail.MailID,
                MailType = mail.MailType,
                PrimaryMail = mail.PrimaryMail,
                UserID = mail.UserID
            };
        }
        private Role ConvertToModelRole(Entities.Role role)
        {
            return new Role {
                Description = role.Description,
                LoweredRoleName = role.LoweredRoleName,
                RoleID = role.RoleID,
                RoleName = role.RoleName
            };
        }
        #endregion
    }
}
